home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume4 / fill < prev    next >
Encoding:
Text File  |  1989-02-03  |  13.7 KB  |  448 lines

  1. Path: xanth!mcnc!gatech!cwjcc!hal!ncoast!allbery
  2. From: chad@anasaz.UUCP
  3. Newsgroups: comp.sources.misc
  4. Subject: v04i091: simple formatting filter for text editors
  5. Message-ID: <8809241116.AA21251@noao.edu>
  6. Date: 25 Sep 88 01:29:37 GMT
  7. Sender: allbery@ncoast.UUCP
  8. Reply-To: chad@anasaz.UUCP ()
  9. Lines: 436
  10. Approved: allbery@ncoast.UUCP
  11.  
  12. Posting-number: Volume 4, Issue 91
  13. Submitted-by: "A. Nonymous" <chad@anasaz.UUCP>
  14. Archive-name: fill
  15.  
  16. This is another simple filter to make it easier to enter and revise
  17. text from within vi or some other editor.  It provides centering,
  18. filling and justification on selectable margins.
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  fill.c fill.1 Makefile test_file
  28. # Wrapped by chad@dcfinc on Sat Sep 24 01:29:59 1988
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'fill.c' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'fill.c'\"
  32. else
  33. echo shar: Extracting \"'fill.c'\" \(8314 characters\)
  34. sed "s/^X//" >'fill.c' <<'END_OF_FILE'
  35. X/* fill.c - Simple text formatter - 1.7 */
  36. X
  37. X/*
  38. X** fill is a simple text formatter meant to be used from within
  39. X** your editor to provide the same functionality as the ^B command
  40. X** in WordStar.  This presumes your editor can pipe an object through
  41. X** a filter.  In vi, you would do something like "!}fill" to word wrap
  42. X** a paragraph.  Of course, you may, in the spirit of Unix, find other
  43. X** uses for it.  For example, fill has the side-effect of de-tabifying
  44. X** lines passed to it.
  45. X**    Usage: fill [-c | -j] [-l n] [-o n]
  46. X**        -c    center the lines
  47. X**        -j    justify the right margin
  48. X**        -r n    set right margin to "n", defaults to 72
  49. X**        -l n    set left margin to "n", defaults to 1
  50. X*/
  51. X
  52. X/*
  53. X** Author:
  54. X**   Chad R. Larson            This program is placed in the
  55. X**   DCF, Inc.                Public Domain.  You may do with
  56. X**   14623 North 49th Place        it as you please.
  57. X**   Scottsdale, AZ 85254
  58. X*/
  59. X
  60. X/*
  61. X** Programming note:  functions from the string library were used
  62. X** wherever logical, under the assumption that they are more optimized
  63. X** (or assemblerized) than whatever I built would be.  On my C library
  64. X** this is true, your milage may vary.  Buffer pointers were generally
  65. X** avoided for readability (this doesn't have to blaze, after all).
  66. X*/
  67. X
  68. X/* maximum length of a line (for centering only) */
  69. X#define LINE_MAX    512
  70. X
  71. X/* maximum length of a word */
  72. X#define WORD_MAX    128
  73. X
  74. X/* the default right margin */
  75. X#define DEF_MARGIN    72
  76. X
  77. X#include <stdio.h>
  78. X#include <string.h>
  79. X#include <memory.h>
  80. X
  81. X/* forward references */
  82. Xvoid    j_line();    /* justify a line */
  83. Xvoid    exit();
  84. Xchar    *malloc();
  85. X
  86. X
  87. X/* main program */
  88. Xvoid main(argc, argv)
  89. Xint    argc;
  90. Xchar    *argv[];
  91. X{
  92. X    int        c;            /* a generic character */
  93. X    int        center = 0;        /* center text flag */
  94. X    int        justify = 0;        /* justify right margin flag */
  95. X    int        w_length;        /* length of current word */
  96. X    int        l_length = 0;        /* length of current line */
  97. X    int        l_margin = 1;        /* left margin */
  98. X    int        r_margin = DEF_MARGIN;    /* right margin */
  99. X    int        wrap_point;        /* max chars allowed on a line */
  100. X    char    *margin;        /* points to left margin string */
  101. X    char    *out_line;        /* points to the output line */
  102. X    char    word[WORD_MAX];        /* the current word */
  103. X    char    *bp;            /* a buffer pointer for centering */
  104. X    extern char    *optarg;        /* option argument pointer
  105. X
  106. X    /* parse the command line */
  107. X    while ((c = getopt(argc, argv, "cjr:l:")) != EOF)
  108. X    switch (c) {
  109. X    case 'c':
  110. X        center++;
  111. X        break;
  112. X    case 'j':
  113. X        justify++;
  114. X        break;
  115. X    case 'r':
  116. X        r_margin = atoi(optarg);
  117. X        break;
  118. X    case 'l':
  119. X        l_margin = atoi(optarg);
  120. X        break;
  121. X    case '?':
  122. X        (void)fprintf(stderr,
  123. X          "Usage: %s [-c | -j] [-l n] [-o n]\n", argv[0]);
  124. X        exit(-1);
  125. X    }
  126. X
  127. X    /* validate command line inputs */
  128. X    if ( justify && center ) {
  129. X    (void)fputs("Center and Justify are mutually exclusive.\n", stderr);
  130. X    exit(1);
  131. X    }
  132. X    if (l_margin >= r_margin || l_margin < 1) {
  133. X    (void)fputs("Illogical margin setting.\n", stderr);
  134. X    exit(2);
  135. X    }
  136. X
  137. X    /* Center the text if requested.  Will exit without filling. */
  138. X    if (center) {
  139. X    if ( (out_line = malloc(LINE_MAX)) == NULL ) {
  140. X        (void)fputs("Unable to allocate centering buffer.\n", stderr);
  141. X        exit(3);
  142. X    }
  143. X    while ( fgets(out_line, LINE_MAX, stdin) != NULL ) {
  144. X        bp = out_line;
  145. X        while (*bp == ' ' || *bp == '\t')    /* strip leading spaces */
  146. X        bp++;
  147. X        l_length = strlen(bp);
  148. X        l_length--;            /* back over new-line */
  149. X        while (bp[l_length - 1] == ' ' || bp[l_length - 1] == '\t')
  150. X        l_length--;            /* strip trailing space */
  151. X        bp[l_length] = '\0';
  152. X        center = (r_margin - l_length) / 2;
  153. X        while (center--)
  154. X        (void)putc(' ', stdout);
  155. X        (void)puts(bp);
  156. X    }
  157. X    exit(0);
  158. X    }
  159. X
  160. X    /* create the left margin string */
  161. X    if ( (margin = malloc( (unsigned)l_margin) ) == NULL ) {
  162. X    (void)fputs("Unable to allocate space for margin.\n", stderr);
  163. X    exit(4);
  164. X    }
  165. X    (void)memset(margin, ' ', l_margin - 1);
  166. X    margin[l_margin - 1] = '\0';
  167. X
  168. X    /* create the output line buffer */
  169. X    wrap_point = r_margin - l_margin + 1;
  170. X    if ((out_line = malloc( (unsigned)wrap_point + 3) ) == NULL) {
  171. X    (void)fputs("Unable to allocate space for line buffer.\n", stderr);
  172. X    exit(5);
  173. X    }
  174. X
  175. X    /* move words from the input to the output */
  176. X    while ( (w_length = get_word(word) ) != 0 ) {
  177. X    if ( (l_length + w_length) > wrap_point ) {    /* line wrap? */
  178. X        while (out_line[l_length - 1] == ' ')   /* trailing space strip */
  179. X        l_length--;
  180. X        out_line[l_length] = '\0';
  181. X        if (justify)            /* justify the line? */
  182. X        j_line(out_line, wrap_point);
  183. X        (void)fputs(margin, stdout);    /* set any offset */
  184. X        (void)puts(out_line);        /* put the line to stdout */
  185. X        *out_line = '\0';            /* reset the output line */
  186. X        l_length = 0;
  187. X    }
  188. X    (void)strcat(out_line, word);
  189. X    (void)strcat(out_line, " ");
  190. X    l_length = l_length + w_length + 1;
  191. X    if ( (c = word[w_length - 1]) == '.' || c == '?' || c == '!' ) {
  192. X        (void)strcat(out_line, " ");    /* end-of-sentence handling */
  193. X        l_length++;
  194. X    }
  195. X    }
  196. X
  197. X    /* clean up and exit */
  198. X    if (l_length) {        /* residual to flush */
  199. X    while (out_line[l_length - 1] == ' ')
  200. X        l_length--;
  201. X    out_line[l_length] = '\0';
  202. X    (void)fputs(margin, stdout);
  203. X    (void)puts(out_line);
  204. X    }
  205. X    exit(0);
  206. X}
  207. X
  208. X/*
  209. X** get_word - a routine to return the next word from the standard input.
  210. X** Copies the next word from the input stream to the location pointed to
  211. X** by its argument.  The word will be null terminated.  A word is any
  212. X** string of characters delimited by whitespace.  Returns the length
  213. X** of the word.
  214. X*/
  215. X
  216. Xint get_word(Word)
  217. Xchar    *Word;
  218. X{
  219. X    register int    c;    /* generic character */
  220. X    register int    i;    /* a counter */
  221. X
  222. X    /* first strip any leading whitespace */
  223. X    while ((c = getchar()) == ' ' || c == '\n' || c == '\t' || c == '\f') ;
  224. X    if (c == EOF) {
  225. X    *Word = '\0';
  226. X    return 0;
  227. X    } else
  228. X    (void)ungetc(c, stdin);
  229. X
  230. X    /* copy the word */
  231. X    i = 0;
  232. X    while ((c = getchar()) != ' ' && c != '\n'
  233. X      && c != '\t' && c != '\f' && c != EOF) {
  234. X    *Word++ = c;
  235. X    if (++i >= WORD_MAX) {
  236. X        (void)fputs("Encountered word too large.\n", stderr);
  237. X        exit(6);
  238. X    }
  239. X    }
  240. X    *Word = '\0';
  241. X    return i;
  242. X}
  243. X
  244. X/*
  245. X** Routine to justify a line.
  246. X*/
  247. Xvoid j_line(buffer, margin)
  248. Xchar    *buffer;
  249. Xint    margin;
  250. X{
  251. X    static unsigned    direction = 0;    /* which end to we fill from? */
  252. X    static char        *work = NULL;    /* working storage */
  253. X    int            insert;        /* count of places to insert */
  254. X    int            spaces;        /* count of spaces to insert */
  255. X    int            multi;        /* spaces to insert each chance */
  256. X    int            extra;        /* count of extra spaces needed */
  257. X    int            count;        /* loop counter */
  258. X    int            loop;        /* loop counter */
  259. X    char        *Ibp;        /* Input buffer pointer */
  260. X    char        *Obp;        /* Output buffer pointer */
  261. X
  262. X    /*
  263. X    ** Allocate a working storage large enough to hold the line.  We
  264. X    ** only do this once (and only if we are justifing).
  265. X    */
  266. X    if (work == NULL)
  267. X    if ((work = malloc( (unsigned)margin + 1 )) == NULL) {
  268. X        (void)fputs("Unable to allocate work buffer.\n", stderr);
  269. X        exit(7);
  270. X    }
  271. X
  272. X    /* how many spaces do we have to insert? */
  273. X    loop = strlen(buffer);
  274. X    spaces = margin - loop;
  275. X    if (spaces == 0)
  276. X    return;
  277. X
  278. X    /* find how many opportunities there are for space stuffing */
  279. X    Ibp = buffer;
  280. X    insert = 0;
  281. X    while (loop--) {
  282. X    if ( (*Ibp++ == ' ') && (*Ibp != ' ') )
  283. X        insert++;
  284. X    }
  285. X    if (insert == 0)
  286. X    return;
  287. X
  288. X    /* how many spaces do we have to stuff per chance? */
  289. X    extra = spaces % insert;        /* extra spaces needed */
  290. X    multi = spaces / insert;        /* spaces per slot to insert */
  291. X
  292. X    /* copy the buffer contents, inserting spaces */
  293. X    direction = ~direction;        /* flip end to fill from */
  294. X    (void)strcpy(work, buffer);        /* make a working copy */
  295. X    if (direction) {
  296. X    Ibp = work;
  297. X    Obp = buffer;
  298. X    loop = strlen(buffer) + 1;
  299. X    while (loop--) {
  300. X        *Obp++ = *Ibp++;        /* move a character */
  301. X        if ((*(Ibp - 1) == ' ') && (*(Ibp - 2) != ' ')) {
  302. X        if (extra) {
  303. X            extra--;
  304. X            *Obp++ = ' ';
  305. X        }
  306. X        for (count = multi; count; count--)
  307. X            *Obp++ = ' ';
  308. X        }
  309. X    }
  310. X    } else {
  311. X    loop = strlen(buffer);
  312. X    Ibp = work + loop;
  313. X    Obp = buffer + loop + spaces;
  314. X    *(Obp + 1) = '\0';
  315. X    while (loop--) {
  316. X        *Obp-- = *Ibp--;
  317. X        if ((*(Ibp + 1) == ' ') && (*(Ibp + 2) != ' ')) {
  318. X        if (extra) {
  319. X            extra--;
  320. X            *Obp-- = ' ';
  321. X        }
  322. X        for (count = multi; count; count--)
  323. X            *Obp-- = ' ';
  324. X        }
  325. X    }
  326. X    }
  327. X}
  328. END_OF_FILE
  329. if test 8314 -ne `wc -c <'fill.c'`; then
  330.     echo shar: \"'fill.c'\" unpacked with wrong size!
  331. fi
  332. # end of 'fill.c'
  333. fi
  334. if test -f 'fill.1' -a "${1}" != "-c" ; then 
  335.   echo shar: Will not clobber existing file \"'fill.1'\"
  336. else
  337. echo shar: Extracting \"'fill.1'\" \(1177 characters\)
  338. sed "s/^X//" >'fill.1' <<'END_OF_FILE'
  339. X.TH FILL 1 local
  340. X.SH NAME
  341. Xfill - a simple text formatter
  342. X.SH SYNOPSIS
  343. Xfill [-c | -j] [-r n] [-l n]
  344. X.SH DESCRIPTION
  345. X.I Fill
  346. Xis a simple text formatter meant to be used from within
  347. Xyour editor to provide the same functionality as the ^B command
  348. Xin WordStar.  This presumes your editor can pipe an object through
  349. Xa filter.  In vi, you would do something like "!}fill" to word wrap
  350. Xa paragraph.  Of course, you may, in the spirit of Unix, find other
  351. Xuses for it.  For example,
  352. X.I fill
  353. Xhas the side-effect of de-tabifying
  354. Xlines passed to it.
  355. X.PP
  356. XThe following options pertain:
  357. X.nf
  358. X    -c    center the lines
  359. X    -j    justify the right margin
  360. X    -r n    set right margin to "n", defaults to 72
  361. X    -l n    set left margin to "n", defaults to 1
  362. X.fi
  363. X.SH CAVEATS
  364. XThis ability is built in to emacs (but then, what isn't).  It is
  365. Xrumored a similar program exists in the Berkely world.
  366. X.SH FEATURES
  367. X.I Fill
  368. Xhas no pracical limit on line lengths (except when centering).
  369. X.SH BUGS
  370. XThe justification algorithm is a little crude.
  371. X.br
  372. X.I Fill
  373. Xmakes no attempt to preserve existing indentations or blank
  374. Xlines (this could be construed as a feature).
  375. X.SH AUTHOR
  376. XChad R. Larson
  377. X.SH "SEE ALSO"
  378. Xpr(1), nroff(1), troff(1)
  379. END_OF_FILE
  380. if test 1177 -ne `wc -c <'fill.1'`; then
  381.     echo shar: \"'fill.1'\" unpacked with wrong size!
  382. fi
  383. # end of 'fill.1'
  384. fi
  385. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  386.   echo shar: Will not clobber existing file \"'Makefile'\"
  387. else
  388. echo shar: Extracting \"'Makefile'\" \(243 characters\)
  389. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  390. X#
  391. X# Makefile for fill, a simple text formatter
  392. X#
  393. X#    Last changed 9/23/88
  394. X#
  395. X
  396. XBINDIR = /usr/local/bin
  397. X
  398. Xfill:    fill.c
  399. X    $(CC) $(CFLAGS) -o fill fill.c
  400. X
  401. Xinstall:    fill
  402. X    strip fill
  403. X    -ln fill $(BINDIR)
  404. X    touch install
  405. X
  406. XLint:    fill.c
  407. X    lint -p fill.c >Lint
  408. END_OF_FILE
  409. if test 243 -ne `wc -c <'Makefile'`; then
  410.     echo shar: \"'Makefile'\" unpacked with wrong size!
  411. fi
  412. # end of 'Makefile'
  413. fi
  414. if test -f 'test_file' -a "${1}" != "-c" ; then 
  415.   echo shar: Will not clobber existing file \"'test_file'\"
  416. else
  417. echo shar: Extracting \"'test_file'\" \(852 characters\)
  418. sed "s/^X//" >'test_file' <<'END_OF_FILE'
  419. XThis is just a silly file of words to see if fill wraps them properly.
  420. XThis is just a silly file of words to see if fill wraps them properly.
  421. XThis is just a silly file of words to see if fill wraps them properly.
  422. XThis is just a silly file of words to see if fill wraps them properly.
  423. XThis is just a silly file of words to see if fill wraps them properly.
  424. XThis is just a silly file of words to see if fill wraps them properly.
  425. XThis is just a silly file of words to see if fill wraps them properly.
  426. XThis is just a silly file of words to see if fill wraps them properly.
  427. XThis is just a silly file of words to see if fill wraps them properly.
  428. XThis is just a silly file of words to see if fill wraps them properly.
  429. XThis is just a silly file of words to see if fill wraps them properly.
  430. XThis is just a silly file of words to see if fill wraps them properly.
  431. END_OF_FILE
  432. if test 852 -ne `wc -c <'test_file'`; then
  433.     echo shar: \"'test_file'\" unpacked with wrong size!
  434. fi
  435. # end of 'test_file'
  436. fi
  437. echo shar: End of shell archive.
  438. exit 0
  439. ---------------
  440. "I read the news today, oh boy!"  --John Lennon
  441. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  442. | DCF, Inc.               | UUCP: ...ncar!noao!nud!anasaz!dcfinc!chad   |
  443. | 14623 North 49th Place  | Ma Bell: (602) 953-1392                     |
  444. | Scottsdale, AZ 85254    | Loran: N-33deg37min20sec W-111deg58min26sec |
  445. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  446. |         Disclaimer: These ARE the opinions of my employer!            |
  447. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  448.